루비로 배우는 객체지향 디자인 | 6장 상속을 이용해 새로운 행동 얻기

날짜
Jul 8, 2024
태그
OOP
설명
자동화된 메시지 전달 시스템
 
상속이란 자동화된 메시지 전달 시스템이다. 명시적으로 메시지를 위임하는 코드를 작성하지 않아도 두 객체 사이의 상속 관계를 정의하면 자동으로 메시지 전달이 이루어진다. 고전적인 상속 관계는 하위 클래스를 만드는 것으로 정의된다. 메시지는 하위 클래스에서 상위 클래스로 전달된다.
 

상속을 사용해야 하는 지점

class Bicycle: def __init__(self, size, tape_color): self.size = size self.tape_color = tape_color # 모든 자전거는 기본값으로 동일한 타이어 크기와 체인 크기를 가집니다. def spares(self): return { 'chain': '10-speed', 'tire_size': '23', 'tape_color': self.tape_color } bike = Bicycle(size='M', tape_color='red') print(bike.size) print(bike.spares())
지금의 Bicycle 클래스는 잘 동작하지만, 변경에 취약한 상태이다.
Bicycle 클래스는 로드 바이크를 기준으로 작성된 상태이다. 만약 산악자전거가 추가된다면 어떨까?
 

자전거 종류가 추가된다면

class Bicycle: def __init__(self, style, size, tape_color, front_shock, rear_shock): self.style = style self.size = size self.tape_color = tape_color self.front_shock = front_shock self.rear_shock = rear_shock # style을 체크하면서 좋지 않은 길로 들어섰다. def spares(self): if self.style == 'road': return { 'chain': '10-speed', 'tire_size': '23', # 밀리미터 'tape_color': self.tape_color } else: return { 'chain': '10-speed', 'tire_size': '2.1', # 인치 'rear_shock': self.rear_shock } bike = Bicycle( style='mountain', size='S', front_shock='Manitou', rear_shock='Fox' ) print(bike.spares()) # {'chain': '10-speed', 'tire_size': '2.1', 'rear_shock': 'Fox'}
이미 구현한 Bicycle 클래스에 산악자전거를 추가하기
 
Bicycle에는 산악자전거에 필요한 기능 중 상당 수가 이미 만들어져 있다. 로드자전거에는 핸들바 테이프가 필요하고, 산악자전거에는 서스펜션이 필요하다는 점만 다를 뿐이다. 대게 이미 구현된 구체 클래스에 코드를 조금 추가해서 문제를 해결하고 싶은 유혹에 빠지기 쉽다. 새로운 패턴을 추가하는 일은 그다지 어렵지 않다. 하지만 변수를 가지고 분기로 처리하는 방식은 여러 좋지 않은 결과를 낳는다. spares 함수는 하나 이상의 책임을 지고 있고, 함수의 주변에는 style 을 체크하려는 코드가 점점 많아질 것이다.
 

숨겨진 타입 찾아내기

변수에 따라 Bicycle을 다른 두 종류로 구분하고 있다. 이 두 종류는 상당한 부분을 공유하고 있지만 스타일의 관점에서 다르다. 하나의 클래스가 여러 개의 서로 다른, 하지만 연관된 타입을 가지고 있다. 이때가 바로 상속을 통해 해결할 수 있는 문제이다. 다시 말해, 밀접히 연관된 타입들이 같은 행동을 고유하고 있지만 특정한 관점에서는 다른 경우인 것이다.
 

상속 관계 그리기

산악자전거는 자전거의 하위 클래스이다.
산악자전거는 자전거의 하위 클래스이다.
 
하위 클래스는 상위클래스의 특수한 형태이다. 산악자전거는 자전거의 모든 행동을 갖고 있고 추가적인 행동을 더 가지고 있어야 한다. 자전거와 협업하는 모든 객체는 산악자전거에 대해 아무것도 모른채 산악자전거와 협업할 수 있어야 한다.
상속이 제대로 작동하려면 두 가지가 언제나 충족되어야 한다.
  1. 모델링하는 객체들이 명백하게 일반-특수 관계를 따라야 한다.
  1. 올바른 코딩 기술을 사용해야 한다.
 
 
자전거의 일반적인 행동과 로드 자전거의 특수한 행동이 섞여있다.
자전거의 일반적인 행동과 로드 자전거의 특수한 행동이 섞여있다.
로드바이크를 기본으로 여기던 Bicycle 클래스에서 로드바이크를 하위클래스로 떼어내야 한다.
 
 

추상화된 상위클래스 만들기

산악자전거와 로드자전거의 상위 클래스인 자전거
산악자전거와 로드자전거의 상위 클래스인 자전거
Bicycle은 공통된 행동을 가지고 MountainBike와 RoadBike에는 각자의 특수한 행동이 추가된다. Bicycle에는 spares와 size가 퍼블릭 인터페이스로 추가되어 있어야 하고, 하위 클래스의 인터페이스에는 각자의 고유한 부품이 추가될 것이다.
 
추상 클래스는 상속받기 위해서 존재한다. 하위 클래스들이 공유하는 공통된 행동들의 저장소이고, 추상 클래스를 상속받은 하위 클래스들은 구체적인 형태를 제공할 수 있다. 두 종류의 자전거를 다뤄야 하는 상황에도 상속을 사용해야 하는 시점은 아닐 수 있다. 상속 관계를 만드는 것은 높은 비용이 든다. 상속 관계를 만들기 전에 한 번 생각해보자.
  • 세 번째 종류의 자전거가 얼마나 더 빨리 필요하게 될 지
  • 중복 코드를 관리하는 비용이 얼마인지
 

요약

공통된 행동을 많이 공유하고 있지만 특정 관점에서만 다르고, 동시에 서로 연관된 타입들을 다루는 문제. 상속은 이러한 문제를 해결해준다. 최소한 세 개의 서로 다른 구체 클래스를 가지고 있다면 올바른 추상을 찾아내는 것은 어려운 일이 아니다. 실제 작업 현장에서는 세 개의 타입이 제공하는 충분한 정보를 얻을 때까지 상속을 미루는 것이 더 좋을 수 있다.
 
 

댓글

guest